
<!DOCTYPE html>
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
		<style>
			body {
				background: black;
				color: rgb(80, 80, 80);
			}
			body, pre, #legend span {
				font-family: Menlo, monospace;
				font-weight: bold;
			}
			#topbar {
				background: black;
				position: fixed;
				top: 0; left: 0; right: 0;
				height: 42px;
				border-bottom: 1px solid rgb(80, 80, 80);
			}
			#content {
				margin-top: 50px;
			}
			#nav, #legend {
				float: left;
				margin-left: 10px;
			}
			#legend {
				margin-top: 12px;
			}
			#nav {
				margin-top: 10px;
			}
			#legend span {
				margin: 0 5px;
			}
			.cov0 { color: rgb(192, 0, 0) }
.cov1 { color: rgb(128, 128, 128) }
.cov2 { color: rgb(116, 140, 131) }
.cov3 { color: rgb(104, 152, 134) }
.cov4 { color: rgb(92, 164, 137) }
.cov5 { color: rgb(80, 176, 140) }
.cov6 { color: rgb(68, 188, 143) }
.cov7 { color: rgb(56, 200, 146) }
.cov8 { color: rgb(44, 212, 149) }
.cov9 { color: rgb(32, 224, 152) }
.cov10 { color: rgb(20, 236, 155) }

		</style>
	</head>
	<body>
		<div id="topbar">
			<div id="nav">
				<select id="files">
				
				<option value="file0">github.com/didi/gatekeeper/middleware/access_control.go (80.0%)</option>
				
				<option value="file1">github.com/didi/gatekeeper/middleware/cluster_auth.go (8.3%)</option>
				
				<option value="file2">github.com/didi/gatekeeper/middleware/http_limit.go (87.5%)</option>
				
				<option value="file3">github.com/didi/gatekeeper/middleware/load_balance.go (62.5%)</option>
				
				<option value="file4">github.com/didi/gatekeeper/middleware/match_rule.go (66.7%)</option>
				
				<option value="file5">github.com/didi/gatekeeper/middleware/recovery.go (40.0%)</option>
				
				<option value="file6">github.com/didi/gatekeeper/middleware/tcp_limit.go (80.0%)</option>
				
				<option value="file7">github.com/didi/gatekeeper/middleware/trace_log.go (82.8%)</option>
				
				</select>
			</div>
			<div id="legend">
				<span>not tracked</span>
			
				<span class="cov0">not covered</span>
				<span class="cov8">covered</span>
			
			</div>
		</div>
		<div id="content">
		
		<pre class="file" id="file0" style="display: none">package middleware

import (
        "errors"
        "github.com/didi/gatekeeper/public"
        "github.com/didi/gatekeeper/service"
        "github.com/gin-gonic/gin"
        "net/http"
)

//权限控制
func AccessControl() gin.HandlerFunc <span class="cov8" title="1">{
        return func(c *gin.Context) </span><span class="cov8" title="1">{
                gws,ok:=c.MustGet(MIDDLEWARE_SERVICE_KEY).(*service.GateWayService)
                if !ok</span><span class="cov0" title="0">{
                        public.ResponseError(c, http.StatusBadRequest, errors.New("gateway_service not valid"))
                        return
                }</span>
                <span class="cov8" title="1">if err := gws.AccessControl(); err != nil </span><span class="cov8" title="1">{
                        public.ResponseError(c, http.StatusUnauthorized, err)
                        return
                }</span>
                <span class="cov8" title="1">c.Set(MIDDLEWARE_SERVICE_KEY,gws)
                c.Next()</span>
        }
}
</pre>
		
		<pre class="file" id="file1" style="display: none">package middleware

import (
        "github.com/didi/gatekeeper/public"
        "github.com/e421083458/golang_common/lib"
        "github.com/gin-gonic/gin"
        "github.com/pkg/errors"
        "net/http"
        "strings"
)

func ClusterAuth() gin.HandlerFunc <span class="cov8" title="1">{
        return func(c *gin.Context) </span><span class="cov0" title="0">{
                clusterList := lib.GetStringConf("base.cluster.cluster_list")
                matchFlag := false
                ipList:=strings.Split(clusterList, ",")
                ipList=append(ipList,"127.0.0.1")
                for _, host := range ipList </span><span class="cov0" title="0">{
                        if c.ClientIP() == host </span><span class="cov0" title="0">{
                                matchFlag = true
                        }</span>
                }
                <span class="cov0" title="0">if !matchFlag </span><span class="cov0" title="0">{
                        public.ResponseError(c, http.StatusBadRequest, errors.New("ClusterAuth error"))
                        return
                }</span>
                <span class="cov0" title="0">c.Next()</span>
        }
}</pre>
		
		<pre class="file" id="file2" style="display: none">package middleware

import (
        "fmt"
        "github.com/didi/gatekeeper/public"
        "github.com/didi/gatekeeper/service"
        "github.com/gin-gonic/gin"
        "github.com/pkg/errors"
        "net/http"
        "strings"
)

func HttpLimit() gin.HandlerFunc <span class="cov8" title="1">{
        return func(c *gin.Context) </span><span class="cov8" title="1">{
                //获取上游服务
                gws, ok := c.MustGet(MIDDLEWARE_SERVICE_KEY).(*service.GateWayService)
                if !ok </span><span class="cov0" title="0">{
                        public.ResponseError(c, http.StatusBadRequest, errors.New("gateway_service not valid"))
                        return
                }</span>

                //入口流量统计
                <span class="cov8" title="1">currentModule := gws.CurrentModule()
                counter := public.FlowCounterHandler.GetRequestCounter(currentModule.Base.Name)
                counter.Increase(c.Request.Context(), c.Request.RemoteAddr)

                //客户端ip限流
                remoteIP := public.Substr(c.Request.RemoteAddr, 0, int64(strings.Index(c.Request.RemoteAddr, ":")))
                if currentModule.AccessControl.ClientFlowLimit &gt; 0 </span><span class="cov8" title="1">{
                        limiter := public.FlowLimiterHandler.GetModuleIPVisitor(currentModule.Base.Name+"_"+remoteIP, currentModule.AccessControl.ClientFlowLimit)
                        if limiter.Allow() == false </span><span class="cov8" title="1">{
                                errmsg := fmt.Sprintf("moduleName:%s remoteIP：%s, Qps limit : %d, %d", currentModule.Base.Name, remoteIP, int64(limiter.Limit()), limiter.Burst())
                                public.ContextWarning(c.Request.Context(), service.DLTagAccessControlFailure, map[string]interface{}{
                                        "msg":        errmsg,
                                        "ip":         remoteIP,
                                        "moduleName": currentModule.Base.Name,
                                })
                                public.ResponseError(c, http.StatusBadRequest, errors.New(errmsg))
                        }</span>
                }
                <span class="cov8" title="1">c.Next()</span>
        }
}
</pre>
		
		<pre class="file" id="file3" style="display: none">package middleware

import (
        "bytes"
        "errors"
        "github.com/didi/gatekeeper/public"
        "github.com/didi/gatekeeper/service"
        "github.com/gin-gonic/gin"
        "io/ioutil"
        "net/http"
)

//负载均衡
func LoadBalance() gin.HandlerFunc <span class="cov8" title="1">{
        return func(c *gin.Context) </span><span class="cov8" title="1">{
                gws,ok:=c.MustGet(MIDDLEWARE_SERVICE_KEY).(*service.GateWayService)
                if !ok</span><span class="cov0" title="0">{
                        public.ResponseError(c, http.StatusBadRequest, errors.New("gateway_service not valid"))
                        return
                }</span>
                <span class="cov8" title="1">proxy, err := gws.LoadBalance()
                if err != nil </span><span class="cov0" title="0">{
                        public.ResponseError(c, http.StatusProxyAuthRequired, err)
                        return
                }</span>
                <span class="cov8" title="1">requestBody,ok:=c.MustGet(MIDDLEWARE_REQUEST_BODY_KEY).([]byte)
                if !ok</span><span class="cov0" title="0">{
                        public.ResponseError(c, http.StatusBadRequest, errors.New("request_body not valid"))
                        return
                }</span>
                <span class="cov8" title="1">c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(requestBody))
                proxy.ServeHTTP(c.Writer, c.Request)
                c.Abort()</span>
        }
}
</pre>
		
		<pre class="file" id="file4" style="display: none">package middleware

import (
        "github.com/didi/gatekeeper/public"
        "github.com/didi/gatekeeper/service"
        "github.com/gin-gonic/gin"
        "net/http"
)

const (
        MIDDLEWARE_SERVICE_KEY = "gateway_service"
        MIDDLEWARE_REQUEST_BODY_KEY = "request_body"
)

//匹配模块
func MatchRule() gin.HandlerFunc <span class="cov8" title="1">{
        return func(c *gin.Context) </span><span class="cov8" title="1">{
                gws := service.NewGateWayService(c.Writer, c.Request)
                if err := gws.MatchRule(); err != nil </span><span class="cov0" title="0">{
                        public.ResponseError(c, http.StatusBadRequest, err)
                        return
                }</span>
                <span class="cov8" title="1">c.Set(MIDDLEWARE_SERVICE_KEY,gws)</span>
        }
}</pre>
		
		<pre class="file" id="file5" style="display: none">package middleware

import (
        "errors"
        "fmt"
        "github.com/didi/gatekeeper/public"
        "github.com/e421083458/golang_common/lib"
        "github.com/gin-gonic/gin"
        "runtime/debug"
)

func Recovery() gin.HandlerFunc <span class="cov8" title="1">{
        return func(c *gin.Context) </span><span class="cov8" title="1">{
                defer func() </span><span class="cov8" title="1">{
                        if err := recover(); err != nil </span><span class="cov0" title="0">{
                                public.ComLogWarning(c, "_panic", map[string]interface{}{
                                        "error": fmt.Sprint(err),
                                        "stack": string(debug.Stack()),
                                })
                                if lib.ConfBase.DebugMode != "debug" </span><span class="cov0" title="0">{
                                        public.ResponseError(c, 500, errors.New("内部错误"))
                                        return
                                }</span> else<span class="cov0" title="0"> {
                                        public.ResponseError(c, 500, errors.New(fmt.Sprint(err)))
                                        return
                                }</span>
                        }
                }()
                <span class="cov8" title="1">c.Next()</span>
        }
}</pre>
		
		<pre class="file" id="file6" style="display: none">package middleware

import (
        "context"
        "fmt"
        "github.com/didi/gatekeeper/dao"
        "github.com/didi/gatekeeper/public"
        "github.com/didi/gatekeeper/service"
        "github.com/didi/gatekeeper/tcpproxy"
        "net"
        "os"
        "strings"
)

//必须返回一个实现该方法的回调函数
func TcpLimit(module *dao.GatewayModule) tcpproxy.HandlerFunc <span class="cov8" title="1">{
        moduleName := module.Base.Name
        qps := module.AccessControl.ClientFlowLimit
        return func(next tcpproxy.Target) tcpproxy.Target </span><span class="cov8" title="1">{
                return tcpproxy.TcpHandlerFunc(func(c net.Conn) </span><span class="cov8" title="1">{
                        //统计
                        counter := public.FlowCounterHandler.GetRequestCounter(moduleName)
                        counter.Increase(context.Background(), c.RemoteAddr().String())
                        remoteIP := public.Substr(c.RemoteAddr().String(), 0,
                                int64(strings.Index(c.RemoteAddr().String(), ":")))
                        if qps &gt; 0 </span><span class="cov8" title="1">{
                                //限流
                                limiter := public.FlowLimiterHandler.GetModuleIPVisitor(moduleName+"_"+remoteIP, qps)
                                if limiter.Allow() == false </span><span class="cov8" title="1">{
                                        errmsg := fmt.Sprintf("moduleName:%s remoteIP：%s, Qps limit : %d, %d", moduleName, remoteIP, int64(limiter.Limit()), limiter.Burst())
                                        public.ContextWarning(context.Background(), service.DLTagAccessControlFailure, map[string]interface{}{
                                                "msg":        errmsg,
                                                "ip":         remoteIP,
                                                "moduleName": module.Base.Name,
                                        })
                                        c.Close()
                                        return
                                }</span>
                        }

                        //白名单限制
                        <span class="cov8" title="1">blackList := strings.Split(module.AccessControl.BlackList, ",")
                        whiteList := strings.Split(module.AccessControl.WhiteList, ",")
                        whiteHostname := strings.Split(module.AccessControl.WhiteHostName, ",")
                        hostname, _ := os.Hostname()
                        authed := false
                        if module.AccessControl.Open == 0 </span><span class="cov8" title="1">{
                                authed = true
                                public.ContextNotice(context.Background(), service.DLTagAccessControlUndef, map[string]interface{}{
                                        "msg":      "access_control_close",
                                        "clientip": remoteIP,
                                })
                        }</span> else<span class="cov8" title="1"> if public.AuthIpList(remoteIP, blackList) </span><span class="cov0" title="0">{
                                errmsg := "client ip in blacklist"
                                public.ContextWarning(context.Background(), service.DLTagAccessControlFailure, map[string]interface{}{
                                        "msg":       errmsg,
                                        "ip":        remoteIP,
                                        "blackList": blackList,
                                })
                        }</span> else<span class="cov8" title="1"> if public.AuthIpList(remoteIP, whiteList) </span><span class="cov8" title="1">{
                                authed = true
                                public.ContextNotice(context.Background(), service.DLTagAccessControlUndef, map[string]interface{}{
                                        "msg":       "clientip_in_whitelist",
                                        "clientip":  remoteIP,
                                        "whitelist": whiteList,
                                })
                        }</span> else<span class="cov0" title="0"> if public.InStringList(hostname, whiteHostname) </span><span class="cov0" title="0">{
                                authed = true
                                public.ContextNotice(context.Background(), service.DLTagAccessControlUndef, map[string]interface{}{
                                        "msg":           "hostname_in_whitehostlist",
                                        "hostname":      hostname,
                                        "whitehostlist": whiteHostname,
                                })
                        }</span>
                        <span class="cov8" title="1">if authed == false </span><span class="cov0" title="0">{
                                c.Close()
                                return
                        }</span>
                        <span class="cov8" title="1">next.HandleConn(c)</span>
                })
        }
}
</pre>
		
		<pre class="file" id="file7" style="display: none">package middleware

import (
        "bytes"
        "context"
        "github.com/didi/gatekeeper/public"
        "github.com/e421083458/golang_common/lib"
        "github.com/gin-gonic/gin"
        "io/ioutil"
        "time"
)

func RequestInLog(c *gin.Context) <span class="cov8" title="1">{
        traceContext := lib.NewTrace()
        if traceId := c.Request.Header.Get("didi-header-rid"); traceId != "" </span><span class="cov0" title="0">{
                traceContext.TraceId = traceId
        }</span>
        <span class="cov8" title="1">if spanId := c.Request.Header.Get("didi-header-spanid"); spanId != "" </span><span class="cov0" title="0">{
                traceContext.SpanId = spanId
        }</span>
        <span class="cov8" title="1">bodyBytes, rerr := ioutil.ReadAll(c.Request.Body)
        if rerr != nil </span><span class="cov0" title="0">{
                lib.Log.TagError(traceContext, "read_body_err", map[string]interface{}{
                        "uri":    c.Request.RequestURI,
                        "method": c.Request.Method,
                        "args":   c.Request.PostForm,
                        "body":   string(bodyBytes),
                        "from":   c.ClientIP(),
                })
        }</span>
        <span class="cov8" title="1">c.Set(MIDDLEWARE_REQUEST_BODY_KEY,bodyBytes)
        lib.Log.TagInfo(traceContext, "_com_request_in", map[string]interface{}{
                "uri":    c.Request.RequestURI,
                "method": c.Request.Method,
                "args":   c.Request.PostForm,
                "body":   string(bodyBytes),
                "from":   c.ClientIP(),
        })
        c.Set("startExecTime", time.Now())
        c.Set("trace", traceContext)
        c.Request.Header.Set("didi-header-rid", traceContext.TraceId)
        c.Request=c.Request.WithContext(context.WithValue(c.Request.Context(),"trace",traceContext))
        c.Request=c.Request.WithContext(context.WithValue(c.Request.Context(),"request_url",c.Request.URL.Path))
        c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))</span>
}

func RequestOutLog(c *gin.Context) <span class="cov8" title="1">{
        endExecTime := time.Now()
        response, _ := c.Get("response")        //没有response，是因为上游没有设置
        st, stok := c.Get("startExecTime")
        if !stok </span><span class="cov0" title="0">{
                public.ComLogWarning(c, "gin_context_geterr", map[string]interface{}{
                        "uri":      c.Request.RequestURI,
                        "method":   c.Request.Method,
                        "args":     c.Request.PostForm,
                        "from":     c.ClientIP(),
                        "response": response,
                        "key":      "startExecTime",
                })
        }</span>
        <span class="cov8" title="1">startExecTime, ok := st.(time.Time)
        if !ok </span><span class="cov0" title="0">{
                public.ComLogWarning(c, "golang_assertion_err", map[string]interface{}{
                        "uri":      c.Request.RequestURI,
                        "method":   c.Request.Method,
                        "args":     c.Request.PostForm,
                        "from":     c.ClientIP(),
                        "response": response,
                        "key":      "st",
                        "st":       st,
                })
        }</span>
        <span class="cov8" title="1">public.ComLogNotice(c, "_com_request_out", map[string]interface{}{
                "uri":       c.Request.RequestURI,
                "method":    c.Request.Method,
                "args":      c.Request.PostForm,
                "from":      c.ClientIP(),
                "response":  response,
                "proc_time": endExecTime.Sub(startExecTime).Seconds(),
        })</span>
}

func RequestTraceLog() gin.HandlerFunc <span class="cov8" title="1">{
        return func(c *gin.Context) </span><span class="cov8" title="1">{
                RequestInLog(c)
                defer RequestOutLog(c)
                c.Next()
        }</span>
}
</pre>
		
		</div>
	</body>
	<script>
	(function() {
		var files = document.getElementById('files');
		var visible;
		files.addEventListener('change', onChange, false);
		function select(part) {
			if (visible)
				visible.style.display = 'none';
			visible = document.getElementById(part);
			if (!visible)
				return;
			files.value = part;
			visible.style.display = 'block';
			location.hash = part;
		}
		function onChange() {
			select(files.value);
			window.scrollTo(0, 0);
		}
		if (location.hash != "") {
			select(location.hash.substr(1));
		}
		if (!visible) {
			select("file0");
		}
	})();
	</script>
</html>
